package com.je.gateway.config;

import com.ctrip.framework.apollo.Config;
import com.ctrip.framework.apollo.ConfigChangeListener;
import com.ctrip.framework.apollo.ConfigService;
import com.ctrip.framework.apollo.model.ConfigChangeEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
import java.util.Set;

@Configuration
public class RedisConfig {

    private static final Logger logger = LoggerFactory.getLogger(RedisConfig.class);

    /**
     * redis连接
     * @return
     */
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        logger.debug("begin init rbac connection factory!");
        Config config = ConfigService.getConfig("redis");
        JedisConnectionFactory cf = createConnectionFactory(config);
        config.addChangeListener(new RedisConfigListener(cf));
        return cf;
    }

    @Bean("stringRedisTemplate")
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory){
        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
        stringRedisTemplate.setConnectionFactory(redisConnectionFactory);
        return stringRedisTemplate;
    }

    /**
     * 实际使用的redisTemplate，可以直接注入到代码中，直接操作redis
     */
    @Bean("redisTemplate")
    public RedisTemplate<String, Object> redisTemplate() {
        logger.debug("begin init redis template!");
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
        //开启事务
        redisTemplate.setEnableTransactionSupport(true);
        RedisSerializer stringSerializer = new StringRedisSerializer();
        JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();

        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setValueSerializer(jdkSerializationRedisSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        redisTemplate.setHashValueSerializer(jdkSerializationRedisSerializer);
        redisTemplate.setDefaultSerializer(stringSerializer);
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }

    protected static JedisConnectionFactory createConnectionFactory(Config config){
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxIdle(config.getIntProperty("redis.maxIdle",300));
        poolConfig.setMaxTotal(config.getIntProperty("redis.maxTotal",1000));
        poolConfig.setTestOnBorrow(config.getBooleanProperty("redis.testOnBorrow",true));
        poolConfig.setMaxWaitMillis(config.getIntProperty("redis.maxWaitMillis",-1));
        poolConfig.setTestWhileIdle(true);
        poolConfig.setNumTestsPerEvictionRun(10);
        poolConfig.setTimeBetweenEvictionRunsMillis(1000*4);

        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory(poolConfig);
        jedisConnectionFactory.getStandaloneConfiguration().setHostName(config.getProperty("redis.host",""));
        jedisConnectionFactory.getStandaloneConfiguration().setPort(config.getIntProperty("redis.port",6379));
        jedisConnectionFactory.getStandaloneConfiguration().setPassword(config.getProperty("redis.pass",""));
        jedisConnectionFactory.getStandaloneConfiguration().setDatabase(config.getIntProperty("redis.dbindex",0));
        return jedisConnectionFactory;
    }

    protected static class RedisConfigListener implements ConfigChangeListener {

        private JedisConnectionFactory connectionFactory;

        public RedisConfigListener(JedisConnectionFactory connectionFactory) {
            this.connectionFactory = connectionFactory;
        }

        @Override
        public void onChange(ConfigChangeEvent changeEvent) {
            Set<String> changeKeys = changeEvent.changedKeys();
            if(changeKeys == null || changeKeys.isEmpty()){
                return;
            }
            Config config = ConfigService.getConfig(changeEvent.getNamespace());
            this.connectionFactory = createConnectionFactory(config);
        }

    }

}
